//
//  ProgressHUD.swift
//  Extend
//
//  Created by shufang zou on 2017/8/30.
//  Copyright © 2017年 敬信. All rights reserved.
//

import Foundation
import UIKit


private let sn_topBar: Int = 1001

private var baseTextFont     : UIFont  = (App.config?.progressTextFont)!
private var baseCornerRadius : CGFloat = 4;
private var baseTimeInterval : Int     = 3;
private var baseTextColor    : UIColor = (App.config?.progressTextColor!)!
private var baseBackColor    : UIColor = (App.config?.progressBgColor!)!
private var baseSize         : CGSize  = CGSize.init(width: 78, height: 78);  //正方形
private var baseSuccessImage : UIImage = ProgressSDK.imageOfCheckmark;
private var baseErrorImage   : UIImage = ProgressSDK.imageOfCross;
private var baseInfoImage    : UIImage = ProgressSDK.imageOfInfo;
private var dismissClick: () ->() = {
    
}

private var isEnableTouch: Bool?

public class ProgressHUD {
    
    public class func textFont(_ font: UIFont){
        baseTextFont = font;
    }
    public class func cornerRadius(_ radius: CGFloat){
        baseCornerRadius = radius;
    }
    public class func minTimeInterval(_ time: Int){
        baseTimeInterval = time;
    }
    public class func textColor(_ color: UIColor){
        baseTextColor = color;
    }
    public class func backColor(_ color: UIColor){
        baseBackColor = color;
    }
    public class func minSize(_ size: CGSize){
        baseSize = size;
    }
    public class func successImage(_ image: UIImage){
        baseSuccessImage = image;
    }
    public class func errorImage(_ image: UIImage){
        baseErrorImage = image;
    }
    public class func infoImage(_ image: UIImage){
        baseInfoImage = image;
    }
    
    // api changed from v3.3
    
    public class func showTop(_ text: String) {
         ProgressSwift.showOnStatusBar(text, autoClear: true, autoClearTime: baseTimeInterval)
    }
    
    // apis
    public class func successInfo(_ text: String) {
        ProgressSwift.showText(ProgressType.success, text: text, autoClear: true, autoClearTime: baseTimeInterval)
    }
   
    public class func errorInfo(_ text: String) {
        ProgressSwift.showText(ProgressType.error, text: text, autoClear: true, autoClearTime: baseTimeInterval)
    }
 
    public class func info(_ text: String) {
        ProgressSwift.showText(ProgressType.info, text: text, autoClear: true, autoClearTime: baseTimeInterval)
    }
    
    public class func loadingUnClick(click: @escaping () ->()) {
        dismissClick = click
        ProgressSwift.wait("", _enableClick: false)
    }
    
    public class func loadingUnEnableClick() {
        isEnableTouch = false
        ProgressSwift.wait("", _enableClick: true)
    }
    
    public class func loading() {
        ProgressSwift.wait("", _enableClick: true)
    }
    
    public class func loadingText(_ text: String) {
        ProgressSwift.wait(text, _enableClick: true)
    }
    
    public class func loadingImg(_ img: UIImage, _ timeIntercal:Int) {
        ProgressSwift.wait(img, timeIntercal)
    }

    public class func text(_ text: String) {
        ProgressSwift.showText(text)
    }
    
    public class func success(_ text: String) {
        ProgressSwift.showText(text)
    }
    
    public class func error(_ text: String) {
        ProgressSwift.showText(text)
    }
    
    public class func dismiss() {
        ProgressSwift.clear()
    }
}

enum ProgressType{
    case success
    case error
    case info
}


class ProgressSwift: NSObject {
    
    static var windows = Array<UIWindow!>()
    static let rv = UIApplication.shared.keyWindow?.subviews.first as UIView!
    static var timer: DispatchSource!
    static var timerTimes = 0
    
    /* just for iOS 8
     */
    static var degree: Double {
        get {
            return [0, 0, 180, 270, 90][UIApplication.shared.statusBarOrientation.hashValue] as Double
        }
    }
    
    // fix https://github.com/johnlui/SwiftNotice/issues/2
    // thanks broccolii(https://github.com/broccolii) and his PR https://github.com/johnlui/SwiftNotice/pull/5
    static func clear() {
        rv?.gestureRecognizers?.removeAll()
        rv?.isUserInteractionEnabled = true
        self.cancelPreviousPerformRequests(withTarget: self)
        if let _ = timer {
            timer.cancel()
            timer = nil
            timerTimes = 0
        }
        windows.removeAll(keepingCapacity: false)
    }
    
    static func showOnStatusBar(_ text: String, autoClear: Bool, autoClearTime: Int) {
        clear()
        let frame = UIApplication.shared.statusBarFrame
        let window = UIWindow()
        window.backgroundColor = UIColor.clear
        let view = UIView()
        view.backgroundColor = baseBackColor;
        
        let label = UILabel(frame: frame)
        label.textAlignment = NSTextAlignment.center
        label.font = baseTextFont;
        label.textColor = baseTextColor;
        label.text = text
        view.addSubview(label)
        
        window.frame = frame
        view.frame = frame
        
        if let version = Double(UIDevice.current.systemVersion),
            version < 9.0 {
            // change center
            var array = [UIScreen.main.bounds.width, UIScreen.main.bounds.height]
            array = array.sorted(by: <)
            let screenWidth = array[0]
            let screenHeight = array[1]
            let x = [0, screenWidth/2, screenWidth/2, 10, screenWidth-10][UIApplication.shared.statusBarOrientation.hashValue] as CGFloat
            let y = [0, 10, screenHeight-10, screenHeight/2, screenHeight/2][UIApplication.shared.statusBarOrientation.hashValue] as CGFloat
            window.center = CGPoint(x: x, y: y)
            
            // change direction
            window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180))
        }
        
        window.windowLevel = UIWindowLevelStatusBar
        window.isHidden = false
        window.addSubview(view)
        windows.append(window)
        
        var origPoint = view.frame.origin
        origPoint.y = -(view.frame.size.height)
        let destPoint = view.frame.origin
        view.tag = sn_topBar
        
        view.frame = CGRect(origin: origPoint, size: view.frame.size)
        UIView.animate(withDuration: 0.3, animations: {
            view.frame = CGRect(origin: destPoint, size: view.frame.size)
        }, completion: { b in
            if autoClear {
                let selector = #selector(ProgressSwift.hide(_:))
                self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime))
            }
        })
    }
    
  
    static func wait(_ text: String, _ imageNames: Array<UIImage> = Array<UIImage>(), timeInterval: Int = 0, _enableClick: Bool) {
        clear()
        var frame = CGRect();
        frame.size = baseSize;
        let window = UIWindow()
        window.backgroundColor = UIColor.clear;
        let mainView = UIView()
        mainView.layer.cornerRadius = baseCornerRadius;
        mainView.backgroundColor = baseBackColor;
        
        if imageNames.count > 0 {
            if imageNames.count > timerTimes {
                let iv = UIImageView()
                iv.frame = frame;
                iv.image = imageNames.first!
                iv.contentMode = UIViewContentMode.scaleAspectFit
                mainView.addSubview(iv)
                timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: UInt(0)), queue: DispatchQueue.main) as! DispatchSource
                timer.scheduleRepeating(deadline: DispatchTime.now(), interval: DispatchTimeInterval.milliseconds(timeInterval))
                timer.setEventHandler(handler: { () -> Void in
                    let name = imageNames[timerTimes % imageNames.count]
                    iv.image = name
                    timerTimes += 1
                })
                timer.resume()
              
            }
        } else {
            if text.isEmpty {
                frame.size = baseSize;
            }else{
                frame.size = CGSize(width: baseSize.width, height: baseSize.width + 10);
            }
            
            let ai = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.whiteLarge)
            if text.isEmpty {
                ai.frame = CGRect(x: baseSize.width/4, y: baseSize.width/4, width: baseSize.width/2, height: baseSize.width/2)
            }else{
                ai.frame = CGRect(x: baseSize.width/4, y: baseSize.width/4-10, width: baseSize.width/2, height: baseSize.width/2)
            }
            ai.startAnimating()
            mainView.addSubview(ai)
            
            if !text.isEmpty {
                let label = UILabel(frame: CGRect(x: 0, y: baseSize.width-25, width: baseSize.width, height: 30))
                label.font = baseTextFont
                label.textColor = baseTextColor
                label.text = text
                label.textAlignment = NSTextAlignment.center
                mainView.addSubview(label)
            }
        }
        
        window.frame = frame
        mainView.frame = frame
        window.center = rv!.center
        
        if let version = Double(UIDevice.current.systemVersion),
            version < 9.0 {
            // change center
            window.center = getRealCenter()
            // change direction
            window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180))
        }
        
        window.windowLevel = UIWindowLevelAlert
        window.isHidden = false
        window.addSubview(mainView)
        windows.append(window)
        
        mainView.alpha = 0.0
        UIView.animate(withDuration: 0.2, animations: {
            mainView.alpha = 1
        })
        
        if _enableClick == false {
            let gesture = UITapGestureRecognizer(target: self, action: #selector(ProgressSwift.tapOne(_:)))
            rv?.addGestureRecognizer(gesture)
        }
        
        if isEnableTouch == false {
            let gesture = UITapGestureRecognizer(target: self, action: #selector(ProgressSwift.unableTouch(_:)))
            rv?.addGestureRecognizer(gesture)
            rv?.isUserInteractionEnabled = false
        }
    }
    
    //单击
    static func tapOne(_ tap : UIGestureRecognizer) {
        ProgressHUD.dismiss()
        dismissClick()
        rv?.removeGestureRecognizer(tap)
    }
    
    //禁止点击
    static func unableTouch(_ tap : UIGestureRecognizer) {

    }
    
    static func wait(_ img: UIImage, _ timeInterval: Int) {
        clear()
        var frame = CGRect();
        frame.size = baseSize;
        let window = UIWindow()
        window.backgroundColor = UIColor.clear;
        let mainView = UIView()
        mainView.layer.cornerRadius = baseCornerRadius;
        mainView.backgroundColor = baseBackColor;
        
        let iv = UIImageView()
        iv.frame = frame;
        iv.image = img
        iv.contentMode = UIViewContentMode.scaleAspectFit
        mainView.addSubview(iv)
        
        
        frame.size = CGSize(width: baseSize.width, height: baseSize.width + 10);
        iv.frame = CGRect(x: (baseSize.width-img.size.width)/2, y: (baseSize.width-img.size.height-15)/2, width: img.size.width, height: img.size.height)
        
        let label = UILabel(frame: CGRect(x: 0, y: baseSize.width-25, width: baseSize.width, height: 30))
        label.font = baseTextFont
        label.textColor = baseTextColor
        label.text = String(format:"%ds",timeInterval)
        label.textAlignment = NSTextAlignment.center
        mainView.addSubview(label)
        
        timerTimes = timeInterval;
        timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(rawValue: UInt(0)), queue: DispatchQueue.main) as! DispatchSource
        timer.scheduleRepeating(deadline: DispatchTime.now(), interval: DispatchTimeInterval.seconds(1))
        timer.setEventHandler(handler: { () -> Void in
            
            iv.rotate360Degree()
            
            let text = String(format:"%d s",timerTimes)
            let ranStr = "s"
            let attrstring:NSMutableAttributedString = NSMutableAttributedString(string:text)
            let str = NSString(string: text)
            let theRange = str.range(of: ranStr)
            attrstring.addAttribute(NSForegroundColorAttributeName, value: UIColor.lightGray, range: theRange)
            label.attributedText = attrstring
            
            if timerTimes == 0 {
                self.clear()
            }
            timerTimes -= 1
        })
        
        timer.resume()
        window.frame = frame
        mainView.frame = frame
        window.center = rv!.center
        
        if let version = Double(UIDevice.current.systemVersion),
            version < 9.0 {
            // change center
            window.center = getRealCenter()
            // change direction
            window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180))
        }
        
        window.windowLevel = UIWindowLevelAlert
        window.isHidden = false
        window.addSubview(mainView)
        windows.append(window)
        
        mainView.alpha = 0.0
        UIView.animate(withDuration: 0.2, animations: {
            mainView.alpha = 1
        })
    }
    
   
    static func showText(_ text: String, autoClear: Bool=true, autoClearTime: Int = baseTimeInterval) {
        clear()
        let window = UIWindow()
        window.backgroundColor = UIColor.clear
        let mainView = UIView()
        mainView.layer.cornerRadius = baseCornerRadius;
        mainView.backgroundColor = baseBackColor
        let label = UILabel()
        label.text = text
        label.numberOfLines = 0
        label.font = baseTextFont
        label.textAlignment = NSTextAlignment.center
        label.textColor = baseTextColor
        let size = label.sizeThatFits(CGSize(width: UIScreen.main.bounds.width-82, height: CGFloat.greatestFiniteMagnitude))
        label.bounds = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        mainView.addSubview(label)
        
        let superFrame = CGRect(x: 0, y: 0, width: label.frame.width + 50 , height: label.frame.height + 20)
        window.frame = superFrame
        mainView.frame = superFrame
        
        label.center = mainView.center
        window.center = rv!.center
        
        if let version = Double(UIDevice.current.systemVersion),
            version < 9.0 {
            // change center
            window.center = getRealCenter()
            // change direction
            window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180))
        }
        
        window.windowLevel = UIWindowLevelAlert
        window.isHidden = false
        window.addSubview(mainView)
        windows.append(window)
        
        if autoClear {
            
            let selector = #selector(ProgressSwift.hide(_:))
            self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime))
            
        }
    }
    
    static func showText(_ type: ProgressType,text: String, autoClear: Bool, autoClearTime: Int) {
        clear()
        var frame = CGRect();
        frame.size = baseSize;
        let window = UIWindow()
        window.backgroundColor = UIColor.clear
        let mainView = UIView()
        mainView.layer.cornerRadius = baseCornerRadius
        mainView.backgroundColor = baseBackColor
        
        var image = UIImage()
        switch type {
        case .success:
            image = baseSuccessImage;
        case .error:
            image = baseErrorImage;
        case .info:
            image = baseInfoImage
        }
        let checkmarkView = UIImageView(image: image)
        checkmarkView.frame = CGRect(x: baseSize.width*0.3, y: baseSize.width*0.2, width: baseSize.width*0.4, height: baseSize.width*0.4);
        mainView.addSubview(checkmarkView)
        
        let label = UILabel(frame: CGRect(x: 0, y: baseSize.width*0.6, width: baseSize.width, height: baseSize.width*0.4))
        label.font = baseTextFont
        label.textColor = baseTextColor;
        label.text = text
        label.textAlignment = NSTextAlignment.center
        mainView.addSubview(label)
        
        window.frame = frame
        mainView.frame = frame
        window.center = rv!.center
        
        if let version = Double(UIDevice.current.systemVersion),
            version < 9.0 {
            // change center
            window.center = getRealCenter()
            // change direction
            window.transform = CGAffineTransform(rotationAngle: CGFloat(degree * Double.pi / 180))
        }
        
        window.windowLevel = UIWindowLevelAlert
        window.center = rv!.center
        window.isHidden = false

        window.addSubview(mainView)
        windows.append(window)
        
        mainView.alpha = 0.0
        UIView.animate(withDuration: 0.2, animations: {
            mainView.alpha = 1
        })
        
        if autoClear {
            let selector = #selector(ProgressSwift.hide(_:))
            self.perform(selector, with: window, afterDelay: TimeInterval(autoClearTime))
            
        }
    }
    
    // fix https://github.com/johnlui/SwiftNotice/issues/2
    static func hide(_ sender: AnyObject) {
        if let window = sender as? UIWindow {
            
            if let v = window.subviews.first {
                UIView.animate(withDuration: 0.2, animations: {
                    
                    if v.tag == sn_topBar {
                        v.frame = CGRect(x: 0, y: -v.frame.height, width: v.frame.width, height: v.frame.height)
                    }
                    v.alpha = 0
                }, completion: { b in
                    if let index = windows.index(where: { (item) -> Bool in
                        return item == window
                    }) {
                        windows.remove(at: index)
                    }
                })
            }
            
        }
    }
    
    // just for iOS 8
    static func getRealCenter() -> CGPoint {
        if UIApplication.shared.statusBarOrientation.hashValue >= 3 {
            return CGPoint(x: rv!.center.y, y: rv!.center.x)
        } else {
            return rv!.center
        }
    }
}

class ProgressSDK {
    struct Cache {
        static var imageOfCheckmark: UIImage?
        static var imageOfCross: UIImage?
        static var imageOfInfo: UIImage?
    }
    class func draw(_ type: ProgressType) {
        let checkmarkShapePath = UIBezierPath()
        
        // draw circle
        checkmarkShapePath.move(to: CGPoint(x: baseSize.width*0.5, y: baseSize.width*0.25))
        checkmarkShapePath.addArc(withCenter: CGPoint(x: baseSize.width*0.25, y: baseSize.width*0.25), radius: baseSize.width*0.25-0.5, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: true)
        checkmarkShapePath.close()
        
        switch type {
        case .success: // draw checkmark
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.28, y: baseSize.width/2/2))
            checkmarkShapePath.addLine(to: CGPoint(x: baseSize.width/2*0.44, y: baseSize.width/2*0.67))
            checkmarkShapePath.addLine(to: CGPoint(x: baseSize.width/2*0.75, y: baseSize.width/2*0.36))
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.28, y: baseSize.width/2*0.5))
            checkmarkShapePath.close()
        case .error: // draw X
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.28, y: baseSize.width/2*0.28))
            checkmarkShapePath.addLine(to: CGPoint(x: baseSize.width/2*0.72, y: baseSize.width/2*0.72))
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.28, y: baseSize.width/2*0.72))
            checkmarkShapePath.addLine(to: CGPoint(x: baseSize.width/2*0.72, y: baseSize.width/2*0.28))
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.28, y: baseSize.width/2*0.28))
            checkmarkShapePath.close()
        case .info:
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.5, y: baseSize.width/2*0.17))
            checkmarkShapePath.addLine(to: CGPoint(x: baseSize.width/2*0.5, y: baseSize.width/2*0.61))
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.5, y: baseSize.width/2*0.17))
            checkmarkShapePath.close()
            
            UIColor.white.setStroke()
            checkmarkShapePath.stroke()
            
            let checkmarkShapePath = UIBezierPath()
            checkmarkShapePath.move(to: CGPoint(x: baseSize.width/2*0.5, y: baseSize.width/2*0.75))
            checkmarkShapePath.addArc(withCenter: CGPoint(x: baseSize.width/2*0.5, y: baseSize.width/2*0.75), radius: 1, startAngle: 0, endAngle: CGFloat(Double.pi*2), clockwise: true)
            checkmarkShapePath.close()
            
            UIColor.white.setFill()
            checkmarkShapePath.fill()
        }
        
        UIColor.white.setStroke()
        checkmarkShapePath.stroke()
    }
    class var imageOfCheckmark: UIImage {
        if (Cache.imageOfCheckmark != nil) {
            return Cache.imageOfCheckmark!
        }
        UIGraphicsBeginImageContextWithOptions(CGSize(width: baseSize.width/2, height: baseSize.width/2), false, 0)
        
        ProgressSDK.draw(ProgressType.success)
        
        Cache.imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return Cache.imageOfCheckmark!
    }
    class var imageOfCross: UIImage {
        if (Cache.imageOfCross != nil) {
            return Cache.imageOfCross!
        }
        UIGraphicsBeginImageContextWithOptions(CGSize(width: baseSize.width/2, height: baseSize.width/2), false, 0)
        
        ProgressSDK.draw(ProgressType.error)
        
        Cache.imageOfCross = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return Cache.imageOfCross!
    }
    class var imageOfInfo: UIImage {
        if (Cache.imageOfInfo != nil) {
            return Cache.imageOfInfo!
        }
        UIGraphicsBeginImageContextWithOptions(CGSize(width: baseSize.width/2, height: baseSize.width/2), false, 0)
        
        ProgressSDK.draw(ProgressType.info)
        
        Cache.imageOfInfo = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return Cache.imageOfInfo!
    }
}

extension UIWindow{
    func hide(){
        ProgressSwift.hide(self)
    }
}
